package base.reflection_demo.demo_05;

import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.Proxy;

/**
 * 动态代理原理演示
 * 通过反射给在核心业务前后分别添加权限校验和日志记录功能
 *
 * 动态代理：
 *  作用：不用修改源码的基础上对方法增强
 *  分类：基于接口的动态代理（常用）；基于子类的动态代理
 * 基于接口的动态代理：
 *  涉及的类：Proxy，该类是jdk官方提供
 * 如何创建代理对象：
 *  使用Proxy.newProxyInstance()方法
 * 创建代理对象的要求：
 *  被代理的类最少实现一个接口，如果没有则不能使用，（理解为厂商要能够被代理，至少指定这个代理商具备哪些条件，
 *  条件在接口中指定，接口就是用来制定标准。比如电脑代理商，至少具有销售，维修能力标准，一般可以理解为何厂商保持
 *  一致的基本功能就具备了代理资格）
 *
 * newProxyInstance方法参数：
 *  ClassLoader：
 *      用于加载代理对象字节码的，和被代理对象使用相同的类加载器。
 *  Class[]:
 *      用于让代理对象和被代理对象有相同的方法。
 *  InvocationHandler:
 *      用于提供增强的代码，让我们写如何代理的逻辑。我们一般都是写一个该接口的实现类，又或者通过匿名内部类提供。
 *      此接口的实现类是谁用谁写，比如代理对象要用，代理对象的逻辑就要在这里提供。该类提供了一个invoke()接口,
 *      public Object invoke(Object proxy, Method method, Object[] args),用于规定我们提供的逻辑要
 *      放到这里，这样代理框架就能够在调用被代理对象方法时就会转而对invoke()方法的调用，invoke里面增强了我们的逻辑。
 *
 */
@Slf4j
public class DynamicProxyTestByProxy {
    public static void main(String[] args) {
        // 1.正常调用业务,业务逻辑里面填杂了权限和日志功能
        UserDao dao = new UserDaoImpl();
//        dao.register();
//        dao.login();

        //2.将业务逻辑里面权限和日志功能撇除,通过动态代理实现权限和日志功能
        MyInvocationHandler handler = new MyInvocationHandler(dao);//将被代理对象传递过去
        UserDao proxyUserDao = (UserDao) Proxy.newProxyInstance(dao.getClass().getClassLoader(),
                dao.getClass().getInterfaces(),
                handler);
        log.info("Test -> proxy:{}", proxyUserDao);

        proxyUserDao.register();
        proxyUserDao.login();
    }
}
